//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of your
// Microsoft Mobile Device 2003 Software Pre-Release Development Agreement
// or other applicable Microsoft license agreement for the software.
// If you did not accept the terms of such a license, you are not
// authorized to use this source code.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:  

RilSimTKitText.cpp

Abstract:


Notes: 


--*/
/*
#------------------------------------------------------------------------------
#    Revision History
#    Date           Author            Activity ID        Activity Headline
#    2007-04-04    zuoxiaona         CEDB200049197       Modify STK CODE for NULL data -RIL- lampson
#    2007-06-22    qinxuetao         WM600007774         Modify STK input string encoding format, only UCS2 uses "HEX" format  
#------------------------------------------------------------------------------
*/

#include "precomp.h"


HRESULT CRilSimToolkitCommand::ParseTextFormatCommand(DWORD* pdwRetNotifyCode, BYTE* pbFifthByte, DWORD* pdwRetVal)
{
    HRESULT hr = S_OK;
    DWORD dwNotifyCode;
    
    *pbFifthByte = 0;
    *pdwRetVal = SIM_RESPONSE_OK;
    
    // First thing should be the Command ID.
    if (!ParseHexDWord((LPCSTR)m_lpbParse, SIMTKIT_TEXTPARSE_PARSE_LEADINGZERO, dwNotifyCode, (LPCSTR&)m_lpbParse))
    { 
        *pdwRetVal = SIM_RESPONSE_ERR_COMMANDNUMBER;
        hr = E_FAIL;
        goto Exit;
    }

    // Set notify code return result
    *pdwRetNotifyCode = dwNotifyCode;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: Parsing Command 0x%x\r\n"), dwNotifyCode));

    // Parse the rest of the information based on the command ID.
    switch(dwNotifyCode)
    {
        case SIM_NOTIFY_SETUPMENU:
        case SIM_NOTIFY_SELECTITEM:
            hr = ParseSetupMenu(dwNotifyCode, pbFifthByte);
            break;
        case SIM_NOTIFY_PLAYTONE:
            hr = ParsePlayTone();
            break;
        case SIM_NOTIFY_DISPLAYTEXT:
            hr = ParseDisplayText(pbFifthByte);
            break;
        case SIM_NOTIFY_GETINKEY:
            hr = ParseGetInKey(pbFifthByte);
            break;
        case SIM_NOTIFY_GETINPUT:
            hr = ParseGetInput(pbFifthByte);
            break;
        case SIM_NOTIFY_SETUPIDLEMODETEXT:
            hr = ParseSetupIdleModeText();
            break;
        case SIM_NOTIFY_SENDSMS:
        case SIM_NOTIFY_SENDSS:
        case SIM_NOTIFY_SENDUSSD:
        case SIM_NOTIFY_SETUPCALL:
        case SIM_NOTIFY_SENDDTMF:
        case SIM_NOTIFY_OPENCHANNEL:
        case SIM_NOTIFY_CLOSECHANNEL:
        case SIM_NOTIFY_RUNATCOMMAND:
            hr = ParseUnsolicitedData();
            break;
        case SIM_NOTIFY_REFRESH:
            hr = ParseRefresh(pbFifthByte);
            break;          
        case SIM_NOTIFY_EVENTLIST:
            hr = ParseEventList();
            break;          
        case SIM_NOTIFY_LAUNCHBROWSER:
            hr = ParseLaunchBrowser(pbFifthByte);
            break;          
        case SIM_NOTIFY_RECEIVEDATA:
            hr = ParseReceiveData();
            break;          
        case SIM_NOTIFY_SENDDATA:
            hr = ParseSendData();
            break;          
        case SIM_NOTIFY_LANGUAGENOTIFICATION:
            hr = ParseLanguageNotification();
            break;          
        case SIM_NOTIFY_CALLSETUP:
        case SIM_NOTIFY_MORETIME:
        case SIM_NOTIFY_POLLINTERVAL:
        case SIM_NOTIFY_POLLINGOFF:
        case SIM_NOTIFY_LOCALINFO:
        default:
            // We don't understand this command
            RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: Don't understand command %x\r\n"), dwNotifyCode));
            *pdwRetVal = SIM_RESPONSE_ERR_COMMANDTYPE;
            hr = E_FAIL;
            goto Exit;
    } // switch(dwNotifyCode) 

    // Set the return value if parsing of the command failed.
    if (FAILED(hr))
    {
        RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: Parsing of command %x failed.\r\n"), dwNotifyCode));
        *pdwRetVal = SIM_RESPONSE_ERR_VALUESMISSING;
        goto Exit;
    }

Exit:

    return hr;
}



HRESULT CRilSimToolkitCommand::ParseSetupMenu(DWORD dwCommandID, BYTE* pbFifthByte)
{
    BYTE* pbParse;
    DWORD dwLength;
    DWORD dwNumItems;
    DWORD dwSelection;
    DWORD dwHelpInfo;
    DWORD dwIconID = SIMTKIT_INVALID_VALUE;
    DWORD dwDispMode = SIMTKIT_INVALID_VALUE;
    DWORD dwRemoveMenu = 0;
    LPWSTR wszMenuTitle = NULL;
    size_t cbMenuTitleBufSize = 0;
    UINT uCurMenuItem;
    HRESULT hr = S_OK;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::ParseSetupMenu\r\n")));

    pbParse = m_lpbParse;
    dwLength = 0;

    // At this point the notification should be in the form of:
    // Setup Menu:
    //,<numItems>,<selection>,<removemenu>,<helpInfo>,[<alphaId>][,<iconId>,<dispMode>]<CR><LF>
    // Select Item:
    // <numItems>,<selection>,<helpInfo>,<alphaId>[,<iconId>,<dispMode>]<CR><LF>
    //
    // +STGC: <itemId>,<itemText>[,<iconId>,<dispMode>,<nai><CR><LF>
    // [+STGC: <itemId>,<itemText>[,<iconId>,<dispMode>,<nai><CR><LF>
    // [...]]]]

    // ,<numItems>
    // integer: indicates the number of items accessible in the menu structure.
    // 0 is a special case, indicating the existing menu is to be removed 
    // from the ME's menu structure.
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwNumItems, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // ,<selection> 
    // integer: gives preferred user selection method
    // 0 no selection preference
    // 1 soft key selection preferred
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwSelection, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Setup Menu only
    // ,<removemenu>
    if ((SIM_NOTIFY_SETUPMENU == dwCommandID) &&
        (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
         !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwRemoveMenu, (LPCSTR&)pbParse)))
    {
        hr = E_FAIL;
        goto Exit;
    }

    // ,<helpInfo>
    // 0 no help information available
    // 1 help information available
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwHelpInfo, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }


    // [,<alphaId>] string format: using either SMS default alphabet 
    // or UCS2 alpha field coding.

    // Setup Menu command with the RemoveMenu field set or 0 menu items treat the alpha ID as
    // optional.
    if ((SIM_NOTIFY_SETUPMENU == dwCommandID) && 
        ((0 != dwRemoveMenu) || (0 == dwNumItems)) )
    {
        if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
        {
            ParseEncodedText(pbParse, SIMTKIT_TEXT_ENCODING_ALPHAID, wszMenuTitle, cbMenuTitleBufSize, pbParse);
        }
    }
    else
    {
        // For all others, alpha ID is required.
        if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
            !ParseEncodedText(pbParse, SIMTKIT_TEXT_ENCODING_ALPHAID, wszMenuTitle, cbMenuTitleBufSize, pbParse)) 
        {
            hr = E_FAIL;
            goto Exit;
        }
    }
        
    // Optional: <iconId>,<dispMode>
    // Numeric tag for the icon to be displayed - 
    // corresponds to the index in the Image file on the SIM
    // 0 No icon
    // 1..255 Icon tag
    if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
        if (!ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwIconID, (LPCSTR&)pbParse))
        { 
            hr = E_FAIL;
            goto Exit;
        }

        // ,<dispMode>
        // integer: denotes use of associated icon
        // 0 display icon only (replaces any text string or alphaId)
        // 1 display with alpha Id or text string
        if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
            !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDispMode, (LPCSTR&)pbParse)) 
        {
            hr = E_FAIL;
            goto Exit;
        }
    }

    // <CR><LF>
    if (!ParseRspPostfix((LPCSTR)pbParse, (LPCSTR&)pbParse) )
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Parse Menu items, if any are specified.
    if (0 < dwNumItems)
    {
        // Create space for a list of pointers to Menu items
        m_rgpsmi = new LPSIMMENUITEM[dwNumItems];
        if (!m_rgpsmi)
        {
            hr = E_OUTOFMEMORY;
            goto Exit;
        }

        // Parse through and add menu items.
        // ---------------------------------
        // The list of menu items we receive from the radio is indexed
        // starting at 1.
        for (uCurMenuItem = 1; uCurMenuItem <= dwNumItems ; uCurMenuItem++)
        {
            if ( FAILED(ParseMenuItem(pbParse)) )
            {
                hr = E_FAIL;
                goto Exit;
            }       
        }
    }

    // Parsing successful, set proper values for build command functions

    // The radio should not send menu items if the remove menu setting
    // was set, but if any existed, remove them. This way an empty menu is
    // still sent to the simtkit layer to trigger the setup menu removal.
    // This is inefficient but suitable handling of this edge condition.
    if (0 != dwRemoveMenu)
    {
        if (NULL != m_rgpsmi)
        {
            // Free memory
            for (UINT i = 0; i < m_numpsmi; i++)
            {
                delete m_rgpsmi[i];
            }
            delete m_rgpsmi;
            m_rgpsmi = NULL;
        }
        m_numpsmi = 0;
    }
    
    // Encode the HelpInfo setting into the fifthByte field to maintain
    // SIMTKIT compatibility between different notification types.
    if (dwHelpInfo)
    {
        *pbFifthByte |= SIMTKIT_TEXTPARSE_HELPINFO;
    }

    m_pwszAlphaId  = wszMenuTitle;
    m_dwAlphaIdLen = cbMenuTitleBufSize;

    if (SIMTKIT_INVALID_VALUE != dwIconID)
    {
        m_dwIconIdentifier = dwIconID;
    }

    if (SIMTKIT_INVALID_VALUE != dwDispMode)
    {
        m_dwIconQualifier = dwDispMode;
    }

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: ParseSetupMenu: NumItems: %d Menu Name: %s\r\n"), dwNumItems, wszMenuTitle));
    
Exit:

    if (FAILED(hr))
    {
        delete[] wszMenuTitle;

        if (NULL != m_rgpsmi)
        {
            // Free memory
            for (UINT i = 0; i < m_numpsmi; i++)
            {
                delete m_rgpsmi[i];
            }
            delete m_rgpsmi;
            m_rgpsmi = NULL;
        }
        m_numpsmi = 0;
    }

    dwLength = pbParse - m_lpbParse;
    m_lpbParse = pbParse;
    m_dwParseLen -= dwLength;
    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::ParseSetupMenu\r\n")));

    return hr;
}

HRESULT CRilSimToolkitCommand::ParseMenuItem(LPBYTE& rpbParse)
{
    HRESULT hr = S_OK;
    DWORD dwItemID;
    DWORD dwIconID = SIMTKIT_INVALID_VALUE;
    DWORD dwDispMode = SIMTKIT_INVALID_VALUE;
    DWORD dwNAI;
    DWORD dwSize;
    LPWSTR wszItemText = NULL;
    size_t cbItemTextBufSize = 0;
    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::ParseMenuItem\r\n")));

    // A menu item should look like this:
    // +STGC: <itemId>,<itemText>[,<iconId>,<dispMode>[,<nai>]<CR><LF>

    
    if ( !MatchStringBeginning((LPCSTR)rpbParse, "+STGC: ", (LPCSTR&)rpbParse) )
    {
        hr = E_FAIL;
        goto Exit;
    }

    // <itemId>
    if ( !ParseDWord((LPCSTR)rpbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwItemID, (LPCSTR&)rpbParse) )
    {
        hr = E_FAIL;
        goto Exit;
    }

    // ,<itemText>
    if (!MatchStringBeginning((LPCSTR)rpbParse, ",", (LPCSTR&)rpbParse) ||
        !ParseEncodedText(rpbParse, SIMTKIT_TEXT_ENCODING_ALPHAID, wszItemText, cbItemTextBufSize, rpbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Optional: ,<iconId>,<dispMode>,<nai>
    if (MatchStringBeginning((LPCSTR)rpbParse, ",", (LPCSTR&)rpbParse))
    {
        //,<iconId>
        if (!ParseDWord((LPCSTR)rpbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwIconID, (LPCSTR&)rpbParse)) 
        {
            hr = E_FAIL;
            goto Exit;
        }

        // ,<dispMode>
        if (!MatchStringBeginning((LPCSTR)rpbParse, ",", (LPCSTR&)rpbParse) ||
            !ParseDWord((LPCSTR)rpbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDispMode, (LPCSTR&)rpbParse)) 
        {
            hr = E_FAIL;
            goto Exit;
        }

        // [,<nai>]
        if (MatchStringBeginning((LPCSTR)rpbParse, ",", (LPCSTR&)rpbParse))
        {
            if (!ParseDWord((LPCSTR)rpbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwNAI, (LPCSTR&)rpbParse))
            {
                hr = E_FAIL;
                goto Exit;
            }
        }
    }

    // <CR><LF>
    if (!ParseRspPostfix((LPCSTR)rpbParse, (LPCSTR&)rpbParse) )
    {
        hr = E_FAIL;
        goto Exit;
    }

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: ParseMenuItem: ItemID: %d Menu Name: %s\r\n"), dwItemID, wszItemText));

    // Now we can allocate memory -- note that dwLen is the length of the text plus 1
    dwSize = ROUNDTODWORD(sizeof(SIMMENUITEM)) + ROUNDTODWORD(cbItemTextBufSize);
    m_rgpsmi[m_numpsmi] = (SIMMENUITEM *) new BYTE[dwSize];
    memset(m_rgpsmi[m_numpsmi], 0, dwSize);

    m_rgpsmi[m_numpsmi]->cbSize = dwSize;
    m_rgpsmi[m_numpsmi]->dwParams = SIM_PARAM_SIMMENUITEM_IDENTIFIER | SIM_PARAM_SIMMENUITEM_TEXTOFFSET |
                                    SIM_PARAM_SIMMENUITEM_TEXTSIZE;
    m_rgpsmi[m_numpsmi]->dwIdentifier = dwItemID;
    if (SIMTKIT_INVALID_VALUE != dwIconID)
    {
        m_rgpsmi[m_numpsmi]->dwParams |= SIM_PARAM_SIMMENUITEM_ICONID;
        m_rgpsmi[m_numpsmi]->dwIconIdentifier = dwIconID;
    }
    if (SIMTKIT_INVALID_VALUE != dwDispMode)
    {
        m_rgpsmi[m_numpsmi]->dwParams |= SIM_PARAM_SIMMENUITEM_ICONQUALIFIER;
        m_rgpsmi[m_numpsmi]->dwIconQualifier = dwDispMode;
    }
    m_rgpsmi[m_numpsmi]->dwTextSize   = cbItemTextBufSize;
    m_rgpsmi[m_numpsmi]->dwTextOffset = ROUNDTODWORD(sizeof(SIMMENUITEM));
    lstrcpy((TCHAR *) ((LPBYTE) m_rgpsmi[m_numpsmi] + m_rgpsmi[m_numpsmi]->dwTextOffset), wszItemText);

    // Great, we added this menu item, so increase m_numpsmi
    m_numpsmi++;

Exit:
    delete[] wszItemText;        

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::ParseMenuItem\r\n")));

    return hr;
}


HRESULT CRilSimToolkitCommand::ParseDisplayText(BYTE* pbFifthByte)
{
    BYTE* pbParse;
    DWORD dwLength;
    LPWSTR wszText = NULL;
    size_t cbTextBufSize = 0;
    DWORD dwDCS;
    DWORD dwPriority;
    DWORD dwClear;
    DWORD dwIconID = SIMTKIT_INVALID_VALUE;
    DWORD dwDispMode = SIMTKIT_INVALID_VALUE;
    DWORD dwResponse = 0;
    HRESULT hr = S_OK;


    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::ParseDisplayText\r\n")));

    pbParse = m_lpbParse;
    dwLength = 0;

    // At this point the DisplayText notification should be in the form of:
    //
    // ,<dcs>,<text>,<priority>,<clear>[,<iconId>,<dispMode>[,<response>]]

    // ,<dcs> 
    // Data encoding Scheme:
    // 0 7bit GSM default alphabet (packed)
    // 4 8bit data
    // 8 UCS2 alphabet
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDCS, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // ,<text>
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseEncodedText(pbParse, dwDCS, wszText, cbTextBufSize, pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // ,<priority>
    // 0 Normal priority
    // 1 High priority
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwPriority, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // ,<clear>
    // 0 Clear after delay
    // 1 User clears message
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwClear, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Optional [,<iconId>,<dispMode>[,<response>]]
    if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse)) 
    {
        BOOL fKeepParsing = TRUE;
        
        // <iconId>
        ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwIconID, (LPCSTR&)pbParse);

        // ,
        if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
        {
            fKeepParsing = FALSE;
        }

        // <dispMode>
        if (fKeepParsing)
        {
            ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDispMode, (LPCSTR&)pbParse);
        }
        
        // Optional: ,<response>
        if (fKeepParsing && MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse)) 
        {
            // <response>
            if (!ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwResponse, (LPCSTR&)pbParse))
            { 
                hr = E_FAIL;
                goto Exit;
            }
        }
    }

    // <CR><LF>
    if (!ParseRspPostfix((LPCSTR)pbParse, (LPCSTR&)pbParse) )
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Parsing successful, set proper values for build command functions

    // Encode the priority setting into the fifthByte field to maintain
    // SIMTKIT compatibility between different notification types.
    if (dwPriority)
    {
        *pbFifthByte |= SIMTKIT_TEXTPARSE_PRIORITY;
    }

    // Encode the clear setting into the fifthByte field to maintain
    // SIMTKIT compatibility between different notification types.
    if (dwClear)
    {
        *pbFifthByte |= SIMTKIT_TEXTPARSE_CLEAR;
    }

    if (SIMTKIT_INVALID_VALUE != dwIconID)
    {
        m_dwIconIdentifier = dwIconID;
    }

    if (SIMTKIT_INVALID_VALUE != dwDispMode)
    {
        m_dwIconQualifier = dwDispMode;
    }

    if (dwResponse)
    {
        m_fImmediateResponse = TRUE;
    }

    m_pwszText = wszText;
    m_dwTextLen = cbTextBufSize;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: ParseDisplayText: Priority: %d clear: %d immediate: %d Text: %s\r\n"), dwPriority, dwClear, dwResponse, wszText));

Exit:
    if (FAILED(hr))
    {
        delete[] wszText;
    }
    dwLength = pbParse - m_lpbParse;
    m_lpbParse = pbParse;
    m_dwParseLen -= dwLength;
    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::ParseDisplayText\r\n")));

    return hr;
}


HRESULT CRilSimToolkitCommand::ParseSetupIdleModeText(void)
{
    BYTE* pbParse;
    LPWSTR wszText = NULL;
    size_t cbTextBufSize = 0;
    DWORD dwDCS;
    DWORD dwIconID = SIMTKIT_INVALID_VALUE;
    DWORD dwDispMode = SIMTKIT_INVALID_VALUE;
    DWORD dwLength;
    HRESULT hr = S_OK;

    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::ParseSetupIdleModeText\r\n")));

    pbParse = m_lpbParse;
    dwLength = 0;

    // At this point the SetupIdleModeText notification should be in the form of:
    //
    // ,<dcs>,<text>[,<iconId>,<dispMode>]

    // ,<dcs> 
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDCS, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // ,<text>
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseEncodedText(pbParse, dwDCS, wszText, cbTextBufSize, pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Optional: ,<iconId>,<dispMode>
    if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
        if (!ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwIconID, (LPCSTR&)pbParse))
        { 
            hr = E_FAIL;
            goto Exit;
        }

        // ,<dispMode>
        // integer: denotes use of associated icon
        // 0 display icon only (replaces any text string or alphaId)
        // 1 display with alpha Id or text string
        if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
            !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDispMode, (LPCSTR&)pbParse)) 
        {
            hr = E_FAIL;
            goto Exit;
        }
    }

    // <CR><LF>
    if (!ParseRspPostfix((LPCSTR)pbParse, (LPCSTR&)pbParse) )
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Parsing successful, set proper values for build command functions

    m_pwszText = wszText;
    m_dwTextLen = cbTextBufSize;

    if (SIMTKIT_INVALID_VALUE != dwIconID)
    {
        m_dwIconIdentifier = dwIconID;
    }

    if (SIMTKIT_INVALID_VALUE != dwDispMode)
    {
        m_dwIconQualifier = dwDispMode;
    }

Exit:
    if (FAILED(hr))
    {
        delete[] wszText;
    }
    dwLength = pbParse - m_lpbParse;
    m_lpbParse = pbParse;
    m_dwParseLen -= dwLength;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::ParseSetupIdleModeText\r\n")));
    return hr;
}


HRESULT CRilSimToolkitCommand::ParseGetInKey(BYTE* pbFifthByte)
{
    BYTE* pbParse;
    DWORD dwLength;
    DWORD dwDCS;
    DWORD dwResponse;
    DWORD dwHelpInfo;
    DWORD dwIconID = SIMTKIT_INVALID_VALUE;
    DWORD dwDispMode = SIMTKIT_INVALID_VALUE;
    LPWSTR wszText = NULL;
    size_t cbTextBufSize = 0;
    HRESULT hr = S_OK;

    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::ParseGetInKey\r\n")));

    pbParse = m_lpbParse;
    dwLength = 0;

    // At this point the GetInKey notification should be in the form of:
    //
    // ,<dcs>,<text>,<response>,<helpInfo>[,<iconId>,<dispMode>]


    // ,<dcs> 
    // Data encoding Scheme:
    // 0 7bit GSM default alphabet (packed)
    // 4 8bit data
    // 8 UCS2 alphabet
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDCS, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // ,<text>
    // Must manage returned memory
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseEncodedText(pbParse, dwDCS, wszText, cbTextBufSize, pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // ,<response> 
    // integer: expected response character format.
    // Digits (0-9, *, # and +) only
    // SMS default alphabet
    // UCS2 alphabet
    // Yes/No response only
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwResponse, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // ,<helpInfo>
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwHelpInfo, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Optional:
    //[,<iconId>,<dispMode>]
    if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
        // <iconID>
        if (!ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwIconID, (LPCSTR&)pbParse)) 
        {
            hr = E_FAIL;
            goto Exit;
        }
        
        // ,<dispMode>
        if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
            !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDispMode, (LPCSTR&)pbParse)) 
        {
            hr = E_FAIL;
            goto Exit;
        }        
    }

    // <CR><LF>
    if (!ParseRspPostfix((LPCSTR)pbParse, (LPCSTR&)pbParse) )
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Parsing successful, set proper values for build command functions

    switch (dwResponse)
    {
        case SIMTKIT_TEXTPARSE_GETINKEY_DIGITS:
            *pbFifthByte |= SIMTKIT_TEXTPARSE_INPUT_KEYPADDIGITS;
            break;
        case SIMTKIT_TEXTPARSE_GETINKEY_PACKED:
            *pbFifthByte |= SIMTKIT_TEXTPARSE_INPUT_SMDEFAULTALPHABET;
            break;
        case SIMTKIT_TEXTPARSE_GETINKEY_UCS:
            *pbFifthByte |= SIMTKIT_TEXTPARSE_INPUT_UCS2;
            break;    
        case SIMTKIT_TEXTPARSE_GETINKEY_YESNO:
            *pbFifthByte |= SIMTKIT_TEXTPARSE_YESNO;
            break;            
        default:
            break;
    }

    if (dwHelpInfo)
    {
        *pbFifthByte |= SIMTKIT_TEXTPARSE_HELPINFO;
    }

    m_pwszText = wszText;
    m_dwTextLen = cbTextBufSize;

    if (SIMTKIT_INVALID_VALUE != dwIconID)
    {
        m_dwIconIdentifier = dwIconID;
    }

    if (SIMTKIT_INVALID_VALUE != dwDispMode)
    {
        m_dwIconQualifier = dwDispMode;
    }

Exit:
    if (FAILED(hr))
    {
        delete[] wszText;
    }
    dwLength = pbParse - m_lpbParse;
    m_lpbParse = pbParse;
    m_dwParseLen -= dwLength;

   RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::ParseGetInKey\r\n")));
    return hr;
}


HRESULT CRilSimToolkitCommand::ParseGetInput(BYTE* pbFifthByte)
{
    BYTE* pbParse;
    DWORD dwLength;
    DWORD dwDCS;
    DWORD dwResponse;
    DWORD dwEcho;
    DWORD dwMinLength;
    DWORD dwMaxLength;
    DWORD dwHelpInfo;
    DWORD dwIconID = SIMTKIT_INVALID_VALUE;
    DWORD dwDispMode = SIMTKIT_INVALID_VALUE;
    LPWSTR wszTitle = NULL;
    LPWSTR wszDefault = NULL;
    size_t cbTitleBufSize = 0;
    size_t cbDefaultBufSize = 0;
    HRESULT hr = S_OK;

    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::ParseGetInput\r\n")));

    pbParse = m_lpbParse;
    dwLength = 0;

    // At this point the GetInput notification should be in the form of:
    //
    // ,<dcs>,<text>,<response>,<echo>,<helpInfo>,<minLgth>,<maxLgth>
    // [,<dcs>,<default>[,<iconId>,<dispMode>]]

    // ,<dcs> 
    // Data encoding Scheme:
    // 0 7bit GSM default alphabet (packed)
    // 4 8bit data
    // 8 UCS2 alphabet
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDCS, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // ,<text>
    // Must manage returned memory
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseEncodedText(pbParse, dwDCS, wszTitle, cbTitleBufSize, pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // ,<response> 
    // integer: expected response character format.
    // Digits (0-9, *, # and +) only from SMS default alphabet (unpacked)
    // Digits (0-9, *, # and +) only from SMS default alphabet (packed)
    // Digits from UCS2 alphabet
    // SMS default alphabet (unpacked)
    // SMS default alphabet (packed)
    // UCS2 alphabet
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwResponse, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // ,<echo> 
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwEcho, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // ,<helpInfo>
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwHelpInfo, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // ,<minLgth> 
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwMinLength, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // ,<maxLgth> 
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwMaxLength, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Optional:
    // ,<dcs>,<default>
    if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
    
        // <dcs>
        if (!ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDCS, (LPCSTR&)pbParse)) 
        {
            hr = E_FAIL;
            goto Exit;
        }
            
        // ,<default>
        // Must manage returned memory
        if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
            !ParseEncodedText(pbParse, dwDCS, wszDefault, cbDefaultBufSize, pbParse)) 
        {
            hr = E_FAIL;
            goto Exit;
        }

        // Optional:
        //[,<iconId>,<dispMode>]
        if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
        {
            // <iconID>
            if (!ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwIconID, (LPCSTR&)pbParse)) 
            {
                hr = E_FAIL;
                goto Exit;
            }
            
            // ,<dispMode>
            if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
                !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDispMode, (LPCSTR&)pbParse)) 
            {
                hr = E_FAIL;
                goto Exit;
            }        
        }
    }
    
    // Parsing successful, set proper values for build command functions

    switch (dwResponse)
    {
        case SIMTKIT_TEXTPARSE_GETINPUT_DIGIT_UNPACKED:            
            *pbFifthByte |= SIMTKIT_TEXTPARSE_INPUT_KEYPADDIGITS;
            break;
        case SIMTKIT_TEXTPARSE_GETINPUT_DIGIT_PACKED:
            *pbFifthByte |= SIMTKIT_TEXTPARSE_INPUT_KEYPADDIGITS;
            *pbFifthByte |= SIMTKIT_TEXTPARSE_PACKEDRESPONSE;
            break;
        case SIMTKIT_TEXTPARSE_GETINPUT_DIGIT_UCS2:
            // Need to revisit and properly setup results for UCS2.
            break;    
        case SIMTKIT_TEXTPARSE_GETINPUT_ALPHA_UNPACKED:
            *pbFifthByte |= SIMTKIT_TEXTPARSE_INPUT_SMDEFAULTALPHABET;
            break;    
        case SIMTKIT_TEXTPARSE_GETINPUT_ALPHA_PACKED:
            *pbFifthByte |= SIMTKIT_TEXTPARSE_INPUT_SMDEFAULTALPHABET;
            *pbFifthByte |= SIMTKIT_TEXTPARSE_PACKEDRESPONSE;
            break;    
        case SIMTKIT_TEXTPARSE_GETINPUT_ALPHA_UCS2:
            // Need to revisit and properly setup results for UCS2.
            break;    
        default:
            break;
    }

    // <CR><LF>
    if (!ParseRspPostfix((LPCSTR)pbParse, (LPCSTR&)pbParse) )
    {
        hr = E_FAIL;
        goto Exit;
    }

    if (dwEcho)
    {
        *pbFifthByte |= SIMTKIT_TEXTPARSE_NOECHO;
    }


    if (dwHelpInfo)
    {
        *pbFifthByte |= SIMTKIT_TEXTPARSE_HELPINFO;
    }

    m_dwMinResponse = dwMinLength;
    m_dwMaxResponse = dwMaxLength;

    m_pwszText = wszTitle;
    m_dwTextLen = cbTitleBufSize;
    m_pwszDefaultText = wszDefault;
    m_dwDefaultTextLen = cbDefaultBufSize;

    if (SIMTKIT_INVALID_VALUE != dwIconID)
    {
        m_dwIconIdentifier = dwIconID;
    }

    if (SIMTKIT_INVALID_VALUE != dwDispMode)
    {
        m_dwIconQualifier = dwDispMode;
    }

Exit:
    if (FAILED(hr))
    {
        delete[] wszTitle;
        delete[] wszDefault;
    }
    dwLength = pbParse - m_lpbParse;
    m_lpbParse = pbParse;
    m_dwParseLen -= dwLength;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::ParseGetInput\r\n")));
    return hr;
}


HRESULT CRilSimToolkitCommand::ParsePlayTone(void)
{
    BYTE* pbParse;
    LPWSTR wszText = NULL;
    size_t cbTextBufSize = 0;
    DWORD dwLength;
    DWORD dwTone;
    DWORD dwDuration;
    HRESULT hr = S_OK;

    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::ParsePlayTone\r\n")));

    pbParse = m_lpbParse;
    dwLength = 0;

    // At this point the PlayTone notification should be in the form of:
    //
    // [,<alphaId>[,<tone>[,<duration>]]]

    // Optional: ,<alphaId>
    if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
        if (!ParseEncodedText(pbParse, SIMTKIT_TEXT_ENCODING_ALPHAID, wszText, cbTextBufSize, pbParse))
        {
            hr = E_FAIL;
            goto Exit;
        }
    }
    
    // Optional: ,<tone>
    if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
        if(!ParseHexDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_LEADINGZERO, dwTone, (LPCSTR&)pbParse))
        {
            hr = E_FAIL;
            goto Exit;
        }
        m_dwTone = dwTone;
    }
        
    // Optional: ,<duration>
    if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
        if(!ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDuration, (LPCSTR&)pbParse))
        {
            hr = E_FAIL;
            goto Exit;
        }  
        m_dwDuration = dwDuration;
    }
            
    // <CR><LF>
    if (!ParseRspPostfix((LPCSTR)pbParse, (LPCSTR&)pbParse) )
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Parsing successful, set proper values for build command functions

    m_pwszAlphaId  = wszText;
    m_dwAlphaIdLen = cbTextBufSize;

Exit:
    if (FAILED(hr))
    {
        delete[] wszText;
    }
    dwLength = pbParse - m_lpbParse;
    m_lpbParse = pbParse;
    m_dwParseLen -= dwLength;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::ParsePlayTone\r\n")));
    return hr;
}


HRESULT CRilSimToolkitCommand::ParseUnsolicitedData(void)
{
    BYTE* pbParse;
    LPWSTR wszText = NULL;
    size_t cbTextBufSize = 0;
    DWORD dwIconID = SIMTKIT_INVALID_VALUE;
    DWORD dwDispMode = SIMTKIT_INVALID_VALUE;
    DWORD dwLength;
    HRESULT hr = S_OK;

    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::ParseUnsolicitedData\r\n")));

    pbParse = m_lpbParse;
    dwLength = 0;

    // At this point the basic UnsolicitedData notification should be in the form of:
    //
    // [,<alphaId>[,<iconId>,<dispMode>]]

    // Optional: ,<alphaId> 
    if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
        if (!ParseEncodedText(pbParse, SIMTKIT_TEXT_ENCODING_ALPHAID, wszText, cbTextBufSize, pbParse)) 
        {
            hr = E_FAIL;
            goto Exit;
        }
    }

    // Optional: ,<iconId>,<dispMode>
    if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
        if (!ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwIconID, (LPCSTR&)pbParse))
        { 
            hr = E_FAIL;
            goto Exit;
        }

        // ,<dispMode>
        if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
            !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDispMode, (LPCSTR&)pbParse)) 
        {
            hr = E_FAIL;
            goto Exit;
        }
    }

    // <CR><LF>
    if (!ParseRspPostfix((LPCSTR)pbParse, (LPCSTR&)pbParse) )
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Parsing successful, set proper values for build command functions

    if (wszText)
    {
        m_pwszAlphaId  = wszText;
        m_dwAlphaIdLen = cbTextBufSize;
    }

    if (SIMTKIT_INVALID_VALUE != dwIconID)
    {
        m_dwIconIdentifier = dwIconID;
    }

    if (SIMTKIT_INVALID_VALUE != dwDispMode)
    {
        m_dwIconQualifier = dwDispMode;
    }

Exit:
    if (FAILED(hr))
    {
        delete[] wszText;
    }
    dwLength = pbParse - m_lpbParse;
    m_lpbParse = pbParse;
    m_dwParseLen -= dwLength;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::ParseUnsolicitedData\r\n")));
    return hr;
}


HRESULT CRilSimToolkitCommand::ParseRefresh(BYTE* pbFifthByte)
{
    BYTE* pbParse;
    DWORD* pdwFileList = NULL;
    LPBYTE pbFileData = NULL;
    WORD wFileAddress;
    size_t cbFileSize = 0;
    DWORD dwRefMode;
    DWORD dwNumFiles = 0;
    DWORD dwLength;
    DWORD dwCurrentFile;
    HRESULT hr = S_OK;

    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::ParseRefresh\r\n")));

    pbParse = m_lpbParse;
    dwLength = 0;

    // At this point the Refresh notification should be in the form of:
    //
    // ,<refMode>[,<numFiles>,<fileList>]

    // ,<refMode> 
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseHexDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_LEADINGZERO, dwRefMode, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Optional: ,<numFiles>,<fileList>
    if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
        // <numFiles>,
        if (!ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwNumFiles, (LPCSTR&)pbParse) ||
            !MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
        { 
            hr = E_FAIL;
            goto Exit;
        }

        // Create buffer for list of files.
        pdwFileList = new DWORD[dwNumFiles];
        
        // <fileList>
        // string type, hex notation: gives the full paths for the SIM files, 
        // each file being delimited by commas within the string
        for (dwCurrentFile = 0 ; dwCurrentFile < dwNumFiles ; dwCurrentFile++)
        {
            // Get the string encoded hex for the file and convert it to bytes
            // Memory allocated: We must manage the memory returned in pbFileData.
            if (!ParseBytes(pbParse, pbFileData, cbFileSize, pbParse)) 
            {
                hr = E_FAIL;
                goto Exit;
            }

            // Sanity check that we have a correctly formed full path to a
            // elementary file. A full path lists the Master file first which
            // starts with 0x3F
            if (*pbFileData != 0x3F)
            {
                RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: Expected master file 3F in file list, saw %x\r\n"), *pbFileData));
                hr = E_INVALIDARG;
                goto Exit;
            }
            
            // From TLV.cpp ReadFileList()
            // Grab the last word -- we're only interested in the last word in each file
            // Note that we don't check each layer down to make sure it's valid
            // (e.g. matches GSM 11.11, sec 6.2)
            wFileAddress = pbFileData[cbFileSize-2];
            wFileAddress = (WORD) ((wFileAddress << 8) + pbFileData[cbFileSize-1]);

            pdwFileList[dwCurrentFile] = (DWORD) wFileAddress;

            // We are done with the dynamic byte buffer for this file.
            delete[] pbFileData;
            pbFileData = NULL;

            // Check for a separating comma unless this is the last file to parse.
            if (dwCurrentFile != (dwNumFiles - 1))
            {
                if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
                {
                    hr = E_FAIL;
                    goto Exit;
                }
            }
        }

    }

    // <CR><LF>
    if (!ParseRspPostfix((LPCSTR)pbParse, (LPCSTR&)pbParse) )
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Parsing successful, set proper values for build command functions

    *pbFifthByte = (BYTE)dwRefMode;
    
    if (pdwFileList)
    {
        m_pdwFiles = pdwFileList;
        m_dwNumFiles = dwNumFiles;
    }

Exit:
    if (FAILED(hr))
    {
        delete[] pbFileData;
        delete[] pdwFileList;
    }
    dwLength = pbParse - m_lpbParse;
    m_lpbParse = pbParse;
    m_dwParseLen -= dwLength;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::ParseRefresh\r\n")));
    return hr;
}


HRESULT CRilSimToolkitCommand::ParseEventList(void)
{
    BYTE* pbParse;
    LPBYTE pbEventList = NULL;
    size_t cbEventListSize = 0;
    DWORD dwLength;
    HRESULT hr = S_OK;

    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::ParseEventList\r\n")));

    pbParse = m_lpbParse;
    dwLength = 0;

    // At this point the Event List notification should be in the form of:
    //
    // ,<eventList>
    //
    //The event list is encoded as a string of hex bytes.
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Get the string encoded hex for the event list and convert it to bytes
    // Memory allocated: We must manage the memory returned in pbFileData.
    if (!ParseBytes(pbParse, pbEventList, cbEventListSize, pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // <CR><LF>
    if (!ParseRspPostfix((LPCSTR)pbParse, (LPCSTR&)pbParse) )
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Parsing successful, set proper values for build command functions
    m_lpbEventList = pbEventList;
    m_dwEventListLen = cbEventListSize;

Exit:
    if (FAILED(hr))
    {
        delete[] pbEventList;
    }

    dwLength = pbParse - m_lpbParse;
    m_lpbParse = pbParse;
    m_dwParseLen -= dwLength;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::ParseEventList\r\n")));
    return hr;
}

HRESULT CRilSimToolkitCommand::ParseLaunchBrowser(BYTE* pbFifthByte)
{
    BYTE* pbParse;
    BYTE* pbBearerData = NULL;
    DWORD dwLength;
    DWORD dwDCS;
    DWORD dwCmdQualifier;
    LPWSTR wszURL = NULL;
    LPWSTR wszGateway = NULL;
    LPWSTR wszAlphaId = NULL;
    size_t cbURLSize = 0;
    size_t cbBearerSize = 0;
    size_t cbGatewaySize = 0;
    size_t cbAlphaIdSize = 0;
    DWORD dwBrowserId;
    DWORD dwIconID = SIMTKIT_INVALID_VALUE;
    DWORD dwDispMode = SIMTKIT_INVALID_VALUE;
    BOOL fBrowserId = FALSE;
    BOOL fDCS = FALSE;
    DWORD dwNumFiles = 0;
    UINT uCurFile;
    HRESULT hr = S_OK;
    BOOL fKeepParsing = TRUE;
    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::ParseLaunchBrowser\r\n")));

    pbParse = m_lpbParse;
    dwLength = 0;

    // At this point the Launch Browser notification should be in the form of:
    //
    // ,<comQual>,<url>
    // [,<browserId>
    // [,<bearer>
    // [,<numFiles>,<provFiles>
    // [,<dcs>,<gateway>
    // [,<alphaId>
    // [,<iconId>,<dispMode>]]]]]]

    // Parse the command qualifier.
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseHexDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_LEADINGZERO, dwCmdQualifier, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
        hr = E_FAIL;
        goto Exit;
    }
        
    // Parse the mandatory URL. The URL may be blank, signifying the use of the
    // default URL.
    ParseEncodedText(pbParse, SIMTKIT_TEXT_ENCODING_UNPACKED, wszURL, cbURLSize, pbParse);

    // Optional: ,
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
        fKeepParsing = FALSE;        
    }
    
    //  Optional: <browserId>
    if (fKeepParsing)
    {
        fBrowserId = ParseHexDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_LEADINGZERO, dwBrowserId, (LPCSTR&)pbParse);
    }

    if (fKeepParsing)
    {
        // Optional: ,
        if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
        {
            fKeepParsing = FALSE;        
        }    
    }

    if (fKeepParsing)
    {
        // <bearer>
        // Get the string encoded hex for the file and convert it to bytes
        // Memory allocated: We must manage the memory returned in pbFileData.
        ParseBytes(pbParse, pbBearerData, cbBearerSize, pbParse);
    }
    
    if (fKeepParsing)
    {
        // Optional: ,
        if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
        {
            fKeepParsing = FALSE;        
        }    
    }

    if (fKeepParsing)
    {
        // Optional: <numFiles>
        ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwNumFiles, (LPCSTR&)pbParse);
    }

    if (fKeepParsing &&  (0 < dwNumFiles))
    {
        // if there are files listed, a comma here is required.
        if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
        {
            hr = E_FAIL;
            goto Exit;
        }

        // Loop through parsing all files.
        // Create space for a list of pointers to files
        m_rgpsfr = new LPSIMFILEREFERENCE[dwNumFiles];
        if (!m_rgpsfr)
        {
            hr = E_OUTOFMEMORY;
            goto Exit;
        }

        // Parse through and add files.
        // ---------------------------------
        // The list of files we receive from the radio is indexed
        // starting at 1.
        for (uCurFile = 1; uCurFile <= dwNumFiles ; uCurFile++)
        {
            if ( FAILED(ParseProvisionFile(pbParse)) )
            {
                hr = E_FAIL;
                goto Exit;
            }
            if (uCurFile != dwNumFiles)
            {
                // Check for comma on all except last.
                if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
                {
                    hr = E_FAIL;
                    goto Exit;
                }
            }
        }
    }
    else if (fKeepParsing)
    {
        // Optional: , (after numFiles)
        if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
        {
            fKeepParsing = FALSE;        
        }    
    }

    if (fKeepParsing)
    {
        // Optional: , (after Provisioning files)
        if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
        {
            fKeepParsing = FALSE;        
        }    
    }

    if (fKeepParsing)
    {
        // Optional: <dcs>
        fDCS = ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDCS, (LPCSTR&)pbParse);
    }
    
    if (fKeepParsing && fDCS)
    {
        // If DCS is set, comma is required.
        if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
        {
            hr = E_FAIL;
            goto Exit;
        }
        
        // If DCS is set, <gateway> is required.
        if (!ParseEncodedText(pbParse, dwDCS, wszGateway, cbGatewaySize, pbParse)) 
        {
            hr = E_FAIL;
            goto Exit;
        }
    }
    else if (fKeepParsing)
    {
        // Optional: , (after DCS)
        if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
        {
            fKeepParsing = FALSE;        
        }            
    }

    if (fKeepParsing)
    {
        // Optional: , (after Gateway)
        if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
        {
            fKeepParsing = FALSE;        
        }    
    }

    if (fKeepParsing)
    {
        // Optional: <alphaId>
        ParseEncodedText(pbParse, SIMTKIT_TEXT_ENCODING_ALPHAID, wszAlphaId, cbAlphaIdSize, pbParse);
    }

    if (fKeepParsing)
    {
        // Optional:
        //[,<iconId>,<dispMode>]
        if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
        {
            // <iconID>
            if (!ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwIconID, (LPCSTR&)pbParse)) 
            {
                hr = E_FAIL;
                goto Exit;
            }
            
            // ,<dispMode>
            if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
                !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDispMode, (LPCSTR&)pbParse)) 
            {
                hr = E_FAIL;
                goto Exit;
            }        
        }
    }
    
    // <CR><LF>
    if (!ParseRspPostfix((LPCSTR)pbParse, (LPCSTR&)pbParse) )
    {
        hr = E_FAIL;
        goto Exit;
    }
    // Parsing successful, set proper values for build command functions
    *pbFifthByte = (BYTE)dwCmdQualifier;
    m_pwszURL = wszURL;
    m_dwURLLen = cbURLSize;
    if(fBrowserId)
    {
        m_dwBrowserId = dwBrowserId;
    }
    m_lpbBearer = pbBearerData;
    m_dwBearerLen = cbBearerSize;
    m_numpsfr = dwNumFiles;
    m_pwszText = wszGateway;
    m_dwTextLen = cbGatewaySize;
    m_pwszAlphaId = wszAlphaId;
    m_dwAlphaIdLen = cbAlphaIdSize;

    if (SIMTKIT_INVALID_VALUE != dwIconID)
    {
        m_dwIconIdentifier = dwIconID;
    }

    if (SIMTKIT_INVALID_VALUE != dwDispMode)
    {
        m_dwIconQualifier = dwDispMode;
    }

Exit:
    if (FAILED(hr))
    {
        delete[] wszURL;
        delete[] pbBearerData;
        delete[] wszGateway;
        delete[] wszAlphaId;

        if (NULL != m_rgpsfr)
        {
            // Free memory
            for (UINT i = 0; i < m_numpsfr; i++)
            {
                delete m_rgpsfr[i];
            }
            delete m_rgpsfr;
            m_rgpsfr = NULL;
        }
        m_numpsfr = 0;
    }

    dwLength = pbParse - m_lpbParse;
    m_lpbParse = pbParse;
    m_dwParseLen -= dwLength;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::ParseLaunchBrowser\r\n")));
    return hr;
}

HRESULT CRilSimToolkitCommand::ParseProvisionFile(LPBYTE& rpbParse)
{
    HRESULT hr = S_OK;
    BYTE* pbFileData = NULL;
    size_t cbFileSize = 0;
    DWORD dwSize;    
    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::ParseProvisionFile\r\n")));

    // A Provision file is a list of bytes.
    if (!ParseBytes(rpbParse, pbFileData, cbFileSize, rpbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    dwSize = ROUNDTODWORD(sizeof(SIMFILEREFERENCE)) + ROUNDTODWORD(cbFileSize);
    m_rgpsfr[m_numpsfr] = NULL;
    m_rgpsfr[m_numpsfr] = (SIMFILEREFERENCE *) new BYTE[dwSize];

    if (NULL != m_rgpsfr[m_numpsfr])
    {
        memset(m_rgpsfr[m_numpsfr], 0, dwSize);
        m_rgpsfr[m_numpsfr]->cbSize = dwSize;
        m_rgpsfr[m_numpsfr]->dwParams = SIM_PARAM_SIMFILEREFERENCE_ALL;
        m_rgpsfr[m_numpsfr]->dwFileSize = cbFileSize;
        m_rgpsfr[m_numpsfr]->dwFileOffset = ROUNDTODWORD(sizeof(SIMFILEREFERENCE));
        memcpy(((LPBYTE) m_rgpsfr[m_numpsfr] + m_rgpsfr[m_numpsfr]->dwFileOffset), pbFileData, cbFileSize);

        // Great, we added this file, so increase the count
        m_numpsfr++;
    }
    else
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

Exit:
    delete[] pbFileData;        

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::ParseProvisionFile\r\n")));

    return hr;
}

HRESULT CRilSimToolkitCommand::ParseReceiveData(void)
{
    BYTE* pbParse;
    LPWSTR wszText = NULL;
    size_t cbTextBufSize = 0;
    DWORD dwIconID = SIMTKIT_INVALID_VALUE;
    DWORD dwDispMode = SIMTKIT_INVALID_VALUE;
    DWORD dwChannelDataLength;
    DWORD dwLength;
    HRESULT hr = S_OK;

    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::ParseReceiveData\r\n")));

    pbParse = m_lpbParse;
    dwLength = 0;

    // At this point the Receive Data notification should be in the form of:
    //
    // ,<length>[,<alphaId>[,<iconId>,<dispMode>]]


    // ,<length>
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwChannelDataLength, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Optional: ,<alphaId> 
    if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
        if (!ParseEncodedText(pbParse, SIMTKIT_TEXT_ENCODING_ALPHAID, wszText, cbTextBufSize, pbParse)) 
        {
            hr = E_FAIL;
            goto Exit;
        }
    }

    // Optional: ,<iconId>,<dispMode>
    if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
        if (!ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwIconID, (LPCSTR&)pbParse))
        { 
            hr = E_FAIL;
            goto Exit;
        }

        // ,<dispMode>
        if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
            !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDispMode, (LPCSTR&)pbParse)) 
        {
            hr = E_FAIL;
            goto Exit;
        }
    }

    // <CR><LF>
    if (!ParseRspPostfix((LPCSTR)pbParse, (LPCSTR&)pbParse) )
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Parsing successful, set proper values for build command functions
    m_dwChannelDataLength = dwChannelDataLength;

    if (wszText)
    {
        m_pwszAlphaId  = wszText;
        m_dwAlphaIdLen = cbTextBufSize;
    }

    if (SIMTKIT_INVALID_VALUE != dwIconID)
    {
        m_dwIconIdentifier = dwIconID;
    }

    if (SIMTKIT_INVALID_VALUE != dwDispMode)
    {
        m_dwIconQualifier = dwDispMode;
    }

Exit:
    if (FAILED(hr))
    {
        delete[] wszText;
    }
    dwLength = pbParse - m_lpbParse;
    m_lpbParse = pbParse;
    m_dwParseLen -= dwLength;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::ParseReceiveData\r\n")));
    return hr;
}

HRESULT CRilSimToolkitCommand::ParseSendData(void)
{
    BYTE* pbParse;
    LPWSTR wszText = NULL;
    size_t cbTextBufSize = 0;
    DWORD dwIconID = SIMTKIT_INVALID_VALUE;
    DWORD dwDispMode = SIMTKIT_INVALID_VALUE;
    DWORD dwDataLength;
    BYTE* pbData = NULL;
    size_t cbDataSize;
    DWORD dwLength;
    HRESULT hr = S_OK;

    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::ParseSendData\r\n")));

    pbParse = m_lpbParse;
    dwLength = 0;

    // At this point the Receive Data notification should be in the form of:
    //
    // ,<length>,<data>[,<alphaId>[,<iconId>,<dispMode>]]


    // ,<length>
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
        !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDataLength, (LPCSTR&)pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // ,
    if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
        hr = E_FAIL;
        goto Exit;
    }
    
    // <data>
    if (!ParseBytes(pbParse, pbData, cbDataSize, pbParse)) 
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Optional: ,<alphaId> 
    if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
        if (!ParseEncodedText(pbParse, SIMTKIT_TEXT_ENCODING_ALPHAID, wszText, cbTextBufSize, pbParse)) 
        {
            hr = E_FAIL;
            goto Exit;
        }
    }

    // Optional: ,<iconId>,<dispMode>
    if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
        if (!ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwIconID, (LPCSTR&)pbParse))
        { 
            hr = E_FAIL;
            goto Exit;
        }

        // ,<dispMode>
        if (!MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse) ||
            !ParseDWord((LPCSTR)pbParse, SIMTKIT_TEXTPARSE_PARSE_NOLEADINGZERO, dwDispMode, (LPCSTR&)pbParse)) 
        {
            hr = E_FAIL;
            goto Exit;
        }
    }

    // <CR><LF>
    if (!ParseRspPostfix((LPCSTR)pbParse, (LPCSTR&)pbParse) )
    {
        hr = E_FAIL;
        goto Exit;
    }

    // Parsing successful, set proper values for build command functions
    ASSERT(dwDataLength == cbDataSize);
    
    m_dwChannelDataLen = dwDataLength;
    m_lpbChannelData = pbData;
    
    if (wszText)
    {
        m_pwszAlphaId  = wszText;
        m_dwAlphaIdLen = cbTextBufSize;
    }

    if (SIMTKIT_INVALID_VALUE != dwIconID)
    {
        m_dwIconIdentifier = dwIconID;
    }

    if (SIMTKIT_INVALID_VALUE != dwDispMode)
    {
        m_dwIconQualifier = dwDispMode;
    }

Exit:
    if (FAILED(hr))
    {
        delete[] wszText;
        delete[] pbData;
    }
    dwLength = pbParse - m_lpbParse;
    m_lpbParse = pbParse;
    m_dwParseLen -= dwLength;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::ParseSendData\r\n")));
    return hr;
}

HRESULT CRilSimToolkitCommand::ParseLanguageNotification(void)
{
    BYTE* pbParse;
    DWORD dwLength;
    LPSTR szLanguage = NULL;    
    size_t cbLanguageSize = 0;
    int iWideLength;
    HRESULT hr = S_OK;


    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CRilSimToolkitCommand::ParseLanguageNotification\r\n")));

    pbParse = m_lpbParse;
    dwLength = 0;

    // At this point the Language notification should be in the form of:
    //
    // [,<language>]
    // where language is a pair of alpha numeric characters.

    if (MatchStringBeginning((LPCSTR)pbParse, ",", (LPCSTR&)pbParse))
    {
        if (!ParseUnlimitedUnquotedString((LPCSTR)pbParse, '\r', szLanguage, cbLanguageSize, (LPCSTR&)pbParse)) 
        {
            hr = E_FAIL;
            goto Exit;
        }
    }

    // <CR><LF>
    if (!ParseRspPostfix((LPCSTR)pbParse, (LPCSTR&)pbParse) )
    {
        hr = E_FAIL;
        goto Exit;
    }

    // If we received a language, copy it to 
    if ((NULL != szLanguage) && (0 < cbLanguageSize))
    {
        // Size of the receiving language buffer must be the same size
        // as the max number of TCHAR's the SIMLANGUAGE structure can hold.
        if (cbLanguageSize != MAXLEN_LANGUAGE)
        {
            ASSERT(FALSE);
            hr = E_FAIL;
            goto Exit;
        }

        m_pwszLanguage = new TCHAR[MAXLEN_LANGUAGE];
        if (NULL == m_pwszLanguage)
        {
            ASSERT(FALSE);
            hr = E_OUTOFMEMORY;
            goto Exit;
        }

        iWideLength = MultiByteToWideChar(CP_ACP, 0, szLanguage, cbLanguageSize, m_pwszLanguage, MAXLEN_LANGUAGE);
        m_pwszLanguage[MAXLEN_LANGUAGE-1] = TEXT('\0');
        // Set the output size to the size of the buffer, not the character count.
        m_dwLanguageLen = (iWideLength) * sizeof(TCHAR);
    }
    else
    {
        m_pwszLanguage = NULL;
        m_dwLanguageLen = 0;
    }

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: ParseLanguageNotification: %s\r\n"), szLanguage));

Exit:
    if (FAILED(hr))
    {
        delete[] szLanguage;
    }
    dwLength = pbParse - m_lpbParse;
    m_lpbParse = pbParse;
    m_dwParseLen -= dwLength;
    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CRilSimToolkitCommand::ParseLanguageNotification\r\n")));

    return hr;
}

HRESULT CRilSimToolkitResponse::TextFormatResponse(const RILSIMTOOLKITRSP* pRsp, const LPBYTE pDetails, const DWORD dwDetailSize, LPBYTE pbDataRsp, DWORD *pdwDataRspSize)
{
    DWORD dwOriginalSize = *pdwDataRspSize;
    HRESULT hr = S_OK;

    // Assert parameters
    DEBUGCHK(NULL != pRsp);
    DEBUGCHK(NULL != pbDataRsp);
    DEBUGCHK(0 < *pdwDataRspSize);
    
    // Check parameters
    if (NULL == pRsp ||
        NULL == pbDataRsp ||
        0 >= *pdwDataRspSize)
    {
        hr = E_INVALIDARG;
        goto Exit;
    }

    // Check dwParams to make sure the necessary fields are supported
    DEBUGCHK(pRsp->dwParams & RIL_PARAM_SIMTKIT_RSP_TYPE);
    DEBUGCHK(pRsp->dwParams & RIL_PARAM_SIMTKIT_RSP_RESPONSE);

    if (!(pRsp->dwParams & RIL_PARAM_SIMTKIT_RSP_TYPE) ||
        !(pRsp->dwParams & RIL_PARAM_SIMTKIT_RSP_RESPONSE))
    {
        hr = E_INVALIDARG;
        goto Exit;        
    }
        
    // Check the command and build up the appropriate response.
    switch (pRsp->dwType)
    {
        case SIM_NOTIFY_SETUPMENU_REPLY:
            hr = SetupMenuReply(pRsp->dwResponse, pDetails, dwDetailSize, pbDataRsp, pdwDataRspSize);
            break;
        case SIM_NOTIFY_SETUPMENU:
            hr = SetupMenuResponse(pRsp->dwResponse, pbDataRsp, pdwDataRspSize);
            break;
        case SIM_NOTIFY_SELECTITEM:
            hr = SelectItemResponse(pRsp->dwResponse, pDetails, dwDetailSize, pbDataRsp, pdwDataRspSize);
            break;
        case SIM_NOTIFY_PLAYTONE:
            hr = PlayToneResponse(pRsp->dwResponse, pbDataRsp, pdwDataRspSize);
            break;
        case SIM_NOTIFY_DISPLAYTEXT:
            hr = DisplayTextResponse(pRsp->dwResponse, pbDataRsp, pdwDataRspSize);
            break;
        case SIM_NOTIFY_GETINPUT:
        case SIM_NOTIFY_GETINKEY:
            hr = GetInputResponse(pRsp, pDetails, dwDetailSize, pbDataRsp, pdwDataRspSize);
            break;
        case SIM_NOTIFY_SETUPIDLEMODETEXT:
            hr = SetupIdleModeTextResponse(pRsp->dwResponse, pbDataRsp, pdwDataRspSize);
            break;
        case SIM_NOTIFY_SETUPCALL:
            hr = SetupCallResponse(pRsp->dwResponse, pbDataRsp, pdwDataRspSize);
            break;
        case SIM_NOTIFY_EVENTLIST:
            hr = EventListResponse(pRsp->dwResponse, pbDataRsp, pdwDataRspSize);
            break;
        case SIM_NOTIFY_LAUNCHBROWSER:
            hr = LaunchBrowserResponse(pRsp, pbDataRsp, pdwDataRspSize);
            break;
        case SIM_NOTIFY_OPENCHANNEL:
            hr = OpenChannelResponse(pRsp->dwResponse, pbDataRsp, pdwDataRspSize);
            break;
        case SIM_NOTIFY_SENDDTMF:
            hr = SendDTMFResponse(pRsp->dwResponse, pbDataRsp, pdwDataRspSize);
            break;
        case SIM_NOTIFY_SENDSS:
        case SIM_NOTIFY_SENDUSSD:
        case SIM_NOTIFY_SENDSMS:
        case SIM_NOTIFY_REFRESH:
        case SIM_NOTIFY_CLOSECHANNEL:
        case SIM_NOTIFY_RECEIVEDATA:
        case SIM_NOTIFY_SENDDATA:
        case SIM_NOTIFY_LANGUAGENOTIFICATION:
            // There is no need to send a response for these commands
            // when the radio is pre-parsing and sending text formatted
            // notifications.
            *pdwDataRspSize = 0;
            goto Exit;
        case SIM_NOTIFY_CALLSETUP:
        case SIM_NOTIFY_MORETIME:
        case SIM_NOTIFY_POLLINTERVAL:
        case SIM_NOTIFY_POLLINGOFF:
        case SIM_NOTIFY_LOCALINFO:
        default:
            // Radios that pre-parse the SIM toolkit commands and send
            // text formatted notifications do not issue these commands.
            *pdwDataRspSize = 0;
            goto Exit;

    }


Exit:
    if (FAILED(hr))
    {
        *pdwDataRspSize = 0;
        RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: Creation of command response failed.\r\n")));
    }
    else 
    {
        // Assert that we did not fill up the buffer.
        DEBUGCHK(dwOriginalSize > *pdwDataRspSize);
    }

    return hr;
}

HRESULT CRilSimToolkitResponse::TextEventDownload(const DWORD dwEvent, const LPBYTE pData, const DWORD dwDataSize, LPSTR szDataRsp, DWORD *pdwDataRspSize)
{
    DWORD dwOriginalSize = *pdwDataRspSize;
    HRESULT hr = S_OK;

    // Assert parameters
    DEBUGCHK(NULL != szDataRsp);
    DEBUGCHK(0 < *pdwDataRspSize);
    
    // Check parameters
    if (NULL == szDataRsp ||
        0 >= *pdwDataRspSize)
    {
        hr = E_INVALIDARG;
        goto Exit;
    }

    // Check the command and build up the appropriate response.
    switch (dwEvent)
    {
        case SIMTKIT_EVENT_USERACTIVITY:
        case SIMTKIT_EVENT_IDLESCREEN:
        case SIMTKIT_EVENT_BROWSERTERMINATION:
        case SIMTKIT_EVENT_DISPLAYPARAMETERS:
            _snprintf(szDataRsp, *pdwDataRspSize, "%.2x", dwEvent);
            szDataRsp[(*pdwDataRspSize)-1] = '\0';
            *pdwDataRspSize = strlen((char*)szDataRsp)+1;
            break;
        default:
            *pdwDataRspSize = 0;
            goto Exit;
    }

Exit:
    if (FAILED(hr))
    {
        *pdwDataRspSize = 0;
        RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: Creation of Event Download response failed.\r\n")));
    }
    else 
    {
        // Assert that we did not fill up the buffer.
        DEBUGCHK(dwOriginalSize > *pdwDataRspSize);
    }

    return hr;
}


HRESULT CRilSimToolkitResponse::SetupMenuResponse(DWORD dwResponse, BYTE* pbBuffer, DWORD* pdwSize)
{
    DWORD dwActualResponse;
    HRESULT hr = S_OK;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CSimToolkit::SetupMenuResponse\r\n")));

    switch(dwResponse)
    {
        case SIM_RESPONSE_OK_PARTIAL:
        case SIM_RESPONSE_OK:
            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_OK;
            break; 

        default:
            dwActualResponse = SIMTKIT_TEXTPARSE_SETUPMENU_PROBLEM;
            break;
    }

    _snprintf((char*)pbBuffer, *pdwSize, "25,%d", dwActualResponse);
    pbBuffer[(*pdwSize)-1] = '\0';

    *pdwSize = strlen((char*)pbBuffer)+1;
    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CSimToolkit::SetupMenuResponse\r\n")));

    return hr;
    
}


HRESULT CRilSimToolkitResponse::SetupMenuReply(DWORD dwResponse, const LPBYTE pDetails, const DWORD dwDetailSize, BYTE* pbBuffer, DWORD* pdwSize)
{
    SIMTKITRSPITEM* pItemDetails = (SIMTKITRSPITEM*)pDetails;
    HRESULT hr = S_OK;


    if (NULL == pItemDetails)
    {
        DEBUGCHK(FALSE);
        hr = E_INVALIDARG;
        goto Exit;
    }

    // An item identifier is needed.
    if (!(pItemDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_ITEM_ID))
    {
        DEBUGCHK(FALSE);
        return E_INVALIDARG;
        goto Exit;
    }

    if(SIM_RESPONSE_OK_HELP == dwResponse)
    {
        _snprintf((char*)pbBuffer, *pdwSize, "%d,%d", pItemDetails->dwId, SIMTKIT_TEXTPARSE_MAINMENU_HELP); 
    }
    else
    {
        _snprintf((char*)pbBuffer, *pdwSize, "%d", pItemDetails->dwId); 
    }

    *pdwSize = strlen((char*)pbBuffer)+1;        

Exit:
    return hr;
    
}


HRESULT CRilSimToolkitResponse::SelectItemResponse(DWORD dwResponse, const LPBYTE pDetails, const DWORD dwDetailSize, BYTE* pbBuffer, DWORD* pdwSize)
{
    DWORD dwActualResponse;
    SIMTKITRSPITEM* pItemDetails = (SIMTKITRSPITEM*)pDetails;
    BOOL fSendItemID = false;
    HRESULT hr = S_OK;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CSimToolkit::SelectItemResponse\r\n")));

    switch(dwResponse)
    {
        case SIM_RESPONSE_OK_PARTIAL:
        case SIM_RESPONSE_OK:
            // An item identifier is needed.
            if ((NULL != pItemDetails) && !(pItemDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_ITEM_ID))
            {
                DEBUGCHK(FALSE);
                return E_INVALIDARG;
                goto Exit;
            }

            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_OK;
            fSendItemID = true;
            break; 
        case SIM_RESPONSE_OK_ENDSESSION:
            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_TERMINATE;
            fSendItemID = false;
            break; 
        case SIM_RESPONSE_OK_HELP:
            // An item identifier is needed.
            if ((NULL != pItemDetails) && !(pItemDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_ITEM_ID))
            {
                DEBUGCHK(FALSE);
                return E_INVALIDARG;
                goto Exit;
            }

            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_HELP;
            fSendItemID = true;
            break;
        case SIM_RESPONSE_OK_BACK:
            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_BACK;
            fSendItemID = false;
            break; 
        default:
            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_NORESPONSE;
            fSendItemID = false;
            break;
    }

    if (fSendItemID)
    {
        _snprintf((char*)pbBuffer, *pdwSize, "24,%d,%d", dwActualResponse, pItemDetails->dwId);
    }
    else
    {
        _snprintf((char*)pbBuffer, *pdwSize, "24,%d", dwActualResponse);
    }
    pbBuffer[(*pdwSize)-1] = '\0';

    *pdwSize = strlen((char*)pbBuffer)+1;
    
Exit:
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CSimToolkit::SelectItemResponse\r\n")));
    return hr;
    
}

HRESULT CRilSimToolkitResponse::DisplayTextResponse(DWORD dwResponse, BYTE* pbBuffer, DWORD* pdwSize)
{
    DWORD dwActualResponse;
    HRESULT hr = S_OK;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CSimToolkit::DisplayTextResponse\r\n")));

    // <result> integer: possible values:
    // Message displayed OK
    // Terminate proactive session
    // User cleared message
    // Screen is busy
    // Backward move requested
    // No response from user
    switch(dwResponse)
    {
        case SIM_RESPONSE_OK:
            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_OK;
            break; 
        case SIM_RESPONSE_OK_ENDSESSION:
            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_TERMINATE;
            break; 
        case SIM_RESPONSE_ERR_MOBILEUNABLE:
            dwActualResponse = SIMTKIT_TEXTPARSE_DISPLAYTEXT_BUSY;
            break; 
        case SIM_RESPONSE_OK_BACK:
            dwActualResponse = SIMTKIT_TEXTPARSE_DISPLAYTEXT_BACK;
            break; 
        default:
            dwActualResponse = SIMTKIT_TEXTPARSE_DISPLAYTEXT_NORESPONSE;
            break;
    }

    _snprintf((char*)pbBuffer, *pdwSize, "21,%d", dwActualResponse);
    pbBuffer[(*pdwSize)-1] = '\0';

    *pdwSize = strlen((char*)pbBuffer)+1;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CSimToolkit::DisplayTextResponse\r\n")));
    
    return hr;  
}


HRESULT CRilSimToolkitResponse::GetInputResponse(const RILSIMTOOLKITRSP* pRsp, const LPBYTE pDetails, const DWORD dwDetailSize, BYTE* pbBuffer, DWORD* pdwSize)
{
    SIMTKITRSPTEXT* pTextDetails = (SIMTKITRSPTEXT*)pDetails;
    DWORD dwEncode;
    DWORD dwActualResponse;
    LPWSTR wszText;
    LPSTR szKeyText = NULL;
    UINT uiLen;
    HRESULT hr = S_OK;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CSimToolkit::GetInputResponse\r\n")));

    // A pRsp is needed. 
    if (NULL == pRsp)
    {
        DEBUGCHK(FALSE);
        hr = E_INVALIDARG;
        goto Exit;
    }

    // Make sure the appropriate elements of the response is there.
    if ( !(RIL_PARAM_SIMTKIT_RSP_RESPONSE & pRsp->dwParams) ||
         !(RIL_PARAM_SIMTKIT_RSP_TYPE & pRsp->dwParams) )
    {
        DEBUGCHK(FALSE);
        hr = E_INVALIDARG;
        goto Exit;        
    }  

    // +STCR=22,<result>[,<dcs>,<text>]
    // <result> integer: possible values:
    // 0 Data entered OK
    // 1    Terminate proactive session
    // 2    Help information requested
    // 3    Backward move requested
    // 4    No response from user
    // <dcs> integer: data coding scheme used for <text>.
    //      The schemes used are as per GSM 03.38 for SMS (see [11]). 
    // 0    7bit GSM default alphabet (packed)
    // 4    8bit data
    // 8    UCS2 alphabet
    // <text> string format: text string in <dcs> format
    //   Special cases are:
    // "00" Negative response entered
    // "01" Positive response entered
    // Note
    // The <dcs> and <text> information must be provided for <result>=0 as the SIM 
    // expects the input to be provided in a Text String Data Object in the Terminal 
    // Response SIM command when data has been input.
    switch(pRsp->dwResponse)
    {
        case SIM_RESPONSE_OK:
            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_OK;
            break; 
        case SIM_RESPONSE_OK_ENDSESSION:
            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_TERMINATE;
            break; 
        case SIM_RESPONSE_OK_HELP:
            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_HELP;
            break;
        case SIM_RESPONSE_OK_BACK:
            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_BACK;
            break; 
        case SIM_RESPONSE_ERR_MOBILEUNABLE:
        default:
            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_NORESPONSE;
            break;            
    }

    if (SIMTKIT_TEXTPARSE_RESPONSE_OK == dwActualResponse)
    {
        // The detailed response information is needed at this point.
        if (NULL == pTextDetails)
        {
            DEBUGCHK(FALSE);
            hr = E_INVALIDARG;
            goto Exit;        
        }
        
        // Handle Yes/No response
        if (pTextDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_TEXT_YESNO)
        {
            // Force encoding to zero.
            dwEncode = 0;
            
            if (0 == pTextDetails->dwYesNo)
            {
                wszText = SIMTKIT_TEXTPARSE_NO;
            }
            else
            {
                wszText = SIMTKIT_TEXTPARSE_YES;
            }

            _snprintf((char*)pbBuffer, *pdwSize, "%x,%d,%d,%s", 
                      pRsp->dwType,
                      dwActualResponse,
                      dwEncode,
                      wszText);
        }
        else
        {
            // Figure out what encoding scheme to use. Default to UCS2
            dwEncode = SIMTKIT_TEXT_ENCODING_UCS2;
            if (pTextDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_TEXT_DCS)
            {
                dwEncode = pTextDetails->dwDCS;
            }

            // Set the text if necessary.
            if (pTextDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_TEXT_TEXTOFFSET &&
                pTextDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_TEXT_TEXTSIZE)
            {
                DEBUGCHK(0 < pTextDetails->dwTextOffset);

                wszText = (LPWSTR) ((LPBYTE)pTextDetails + pTextDetails->dwTextOffset);
            }
            else
            {
                // Set the default text, used for sending a empty string.
                wszText = SIMTKIT_TEXTPARSE_EMPTY_STRING;
            }

            // Create a string of encoded semi-byte chars.
            // Memory allocation: Responsible for freeing szKeyText
            if (!CreateEncodedText(dwEncode, wszText, szKeyText, uiLen))
            {
                hr = E_FAIL;
                goto Exit;
            }

            _snprintf((char*)pbBuffer, *pdwSize, "%x,%d,%d,%s", 
                      pRsp->dwType,
                      dwActualResponse,
                      dwEncode,
                      szKeyText);
        }
    }
    else 
    {
        _snprintf((char*)pbBuffer, *pdwSize, "%x,%d", pRsp->dwType, dwActualResponse);
    }
    pbBuffer[*pdwSize-1] = '\0';
    *pdwSize = strlen((char*)pbBuffer)+1;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CSimToolkit::GetInputResponse\r\n")));

Exit:  
    
    delete[] szKeyText;

    return hr;  
}


HRESULT CRilSimToolkitResponse::PlayToneResponse(DWORD dwResponse, BYTE* pbBuffer, DWORD* pdwSize)
{
    DWORD dwActualResponse;
    HRESULT hr = S_OK;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CSimToolkit::PlayToneResponse\r\n")));

    switch(dwResponse)
    {
        case SIM_RESPONSE_OK:
        case SIM_RESPONSE_OK_BACK:
            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_OK;
            break; 
        case SIM_RESPONSE_OK_ENDSESSION:
            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_TERMINATE;
            break; 
        case SIM_RESPONSE_ERR_MOBILEUNABLE:
        default:
            dwActualResponse = SIMTKIT_TEXTPARSE_PLAYTONE_NOTPLAYED;
            break;
    }

    _snprintf((char*)pbBuffer, *pdwSize, "20,%d", dwActualResponse);
    pbBuffer[(*pdwSize)-1] = '\0';

    *pdwSize = strlen((char*)pbBuffer)+1;
    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CSimToolkit::PlayToneResponse\r\n")));

    return hr;
    
}

HRESULT CRilSimToolkitResponse::SetupIdleModeTextResponse(DWORD dwResponse, BYTE* pbBuffer, DWORD* pdwSize)
{
    DWORD dwActualResponse;
    HRESULT hr = S_OK;

   RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CSimToolkit::SetupIdleModeTextResponse\r\n")));

    switch(dwResponse)
    {
        case SIM_RESPONSE_OK:
        case SIM_RESPONSE_OK_BACK:
        case SIM_RESPONSE_OK_ENDSESSION:
            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_OK;
            break;
        case SIM_RESPONSE_ERR_MOBILEUNABLE:            
        default:
            dwActualResponse = SIMTKIT_TEXTPARSE_IDLETEXT_PROBLEM;
            break;
    }

    _snprintf((char*)pbBuffer, *pdwSize, "28,%d", dwActualResponse);
    pbBuffer[(*pdwSize)-1] = '\0';

    *pdwSize = strlen((char*)pbBuffer)+1;
    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CSimToolkit::SetupIdleModeTextResponse\r\n")));

    return hr;
    
}


HRESULT CRilSimToolkitResponse::SetupCallResponse(DWORD dwResponse, BYTE* pbBuffer, DWORD* pdwSize)
{
    DWORD dwActualResponse;
    HRESULT hr = S_OK;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CSimToolkit::SetupCallResponse\r\n")));

    switch(dwResponse)
    {
        case SIM_RESPONSE_OK:
        case SIM_RESPONSE_OK_BACK:
        case SIM_RESPONSE_OK_ENDSESSION:
            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_OK;
            break;
        case SIM_RESPONSE_ERR_CALLSETUPREJECTED:
        case SIM_RESPONSE_ERR_MOBILEUNABLE:            
        default:
            dwActualResponse = SIMTKIT_TEXTPARSE_SETUPCALL_REJECT;
            break;
    }

    _snprintf((char*)pbBuffer, *pdwSize, "10,%d", dwActualResponse);
    pbBuffer[(*pdwSize)-1] = '\0';

    *pdwSize = strlen((char*)pbBuffer)+1;
    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CSimToolkit::SetupCallResponse\r\n")));

    return hr;
    
}


HRESULT CRilSimToolkitResponse::EventListResponse(DWORD dwResponse, BYTE* pbBuffer, DWORD* pdwSize)
{
    DWORD dwActualResponse;
    HRESULT hr = S_OK;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CSimToolkit::EventListResponse\r\n")));

    switch(dwResponse)
    {
        case SIM_RESPONSE_OK:
        case SIM_RESPONSE_OK_BACK:
        case SIM_RESPONSE_OK_ENDSESSION:
            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_OK;
            break;
        default:
            dwActualResponse = SIMTKIT_TEXTPARSE_EVENTLIST_ERROR;
            break;
    }

    _snprintf((char*)pbBuffer, *pdwSize, "5,%d", dwActualResponse);
    pbBuffer[(*pdwSize)-1] = '\0';

    *pdwSize = strlen((char*)pbBuffer)+1;
    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CSimToolkit::EventListResponse\r\n")));

    return hr;
    
}


HRESULT CRilSimToolkitResponse::LaunchBrowserResponse(const RILSIMTOOLKITRSP* pRsp, BYTE* pbBuffer, DWORD* pdwSize)
{
    DWORD dwActualResponse;
    BOOL fAdditionalInfo = FALSE;
    HRESULT hr = S_OK;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CSimToolkit::EventListResponse\r\n")));

    // Parameters checked by calling function
    if (RIL_PARAM_SIMTKIT_RSP_ADDITIONALINFO & pRsp->dwParams)
    {
        fAdditionalInfo = TRUE;    
    }

    // Translate the error
    switch(pRsp->dwResponse)
    {
        case SIM_RESPONSE_OK:
            dwActualResponse = SIMTKIT_TEXTPARSE_RESPONSE_OK;
            break;
        case SIM_RESPONSE_OK_PARTIAL:
            dwActualResponse = SIM_RESPONSE_OK_PARTIAL;
            break;
        case SIM_RESPONSE_OK_MISSINGINFO:
            dwActualResponse = SIM_RESPONSE_OK_MISSINGINFO;
            break;
        case SIM_RESPONSE_ERR_USERREJECTED:
            dwActualResponse = SIMTKIT_TEXTPARSE_LAUNCHBROWSER_USERREJECTED;
            break;
        case SIM_RESPONSE_ERR_BROWSERGENERIC:
            if (fAdditionalInfo)
            {
                switch (pRsp->dwAdditionalInfo)
                {
                    case SIM_RESPONSE_ERR_MOBILEUNABLE_NOCAUSE:
                        dwActualResponse = SIMTKIT_TEXTPARSE_LAUNCHBROWSER_NOCAUSE;
                        break;
                    case SIM_RESPONSE_ERR_LAUNCHBROWSER_BROWSERUNAVAIL:
                        dwActualResponse = SIMTKIT_TEXTPARSE_LAUNCHBROWSER_BROWSERUNAVAIL;
                        break;
                    default:
                        dwActualResponse = SIMTKIT_TEXTPARSE_LAUNCHBROWSER_NOCAUSE;                        
                        break;                        
                }
            }
        case SIM_RESPONSE_ERR_MOBILEINCAPABLE:
            dwActualResponse = SIMTKIT_TEXTPARSE_LAUNCHBROWSER_MOBILEINCAPABLE;
            break;
        default:
            dwActualResponse = SIMTKIT_TEXTPARSE_LAUNCHBROWSER_MOBILEINCAPABLE;
            break;
    }

    _snprintf((char*)pbBuffer, *pdwSize, "15,%d", dwActualResponse);
    pbBuffer[(*pdwSize)-1] = '\0';

    *pdwSize = strlen((char*)pbBuffer)+1;
    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CSimToolkit::EventListResponse\r\n")));

    return hr;
    
}

HRESULT CRilSimToolkitResponse::OpenChannelResponse(DWORD dwResponse, BYTE* pbBuffer, DWORD* pdwSize)
{
    DWORD dwActualResponse;
    HRESULT hr = S_OK;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CSimToolkit::OpenChannelResponse\r\n")));

    switch(dwResponse)
    {
        case SIM_RESPONSE_OK:
        case SIM_RESPONSE_OK_BACK:
        case SIM_RESPONSE_OK_ENDSESSION:
            dwActualResponse = SIMTKIT_TEXTPARSE_OPENCHANNEL_REQUIRED;
            break;
        case SIM_RESPONSE_ERR_USERREJECTED:
        case SIM_RESPONSE_ERR_MOBILEUNABLE:            
        default:
            dwActualResponse = SIMTKIT_TEXTPARSE_OPENCHANNEL_NOTACCEPTED;
            break;
    }

    _snprintf((char*)pbBuffer, *pdwSize, "40,%d", dwActualResponse);
    pbBuffer[(*pdwSize) - 1] = '\0';

    *pdwSize = strlen((char*)pbBuffer) + 1;
    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CSimToolkit::OpenChannelResponse\r\n")));

    return hr;  
}

HRESULT CRilSimToolkitResponse::SendDTMFResponse(DWORD dwResponse, BYTE* pbBuffer, DWORD* pdwSize)
{
    DWORD dwActualResponse;
    HRESULT hr = S_OK;

    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: +CSimToolkit::SendDTMFResponse\r\n")));

    switch(dwResponse)
    {
        case SIM_RESPONSE_OK:
        case SIM_RESPONSE_OK_BACK:
        case SIM_RESPONSE_OK_ENDSESSION:
            dwActualResponse = SIMTKIT_TEXTPARSE_SENDDTMF_REQUIRED;
            break;
        case SIM_RESPONSE_ERR_USERREJECTED:
        case SIM_RESPONSE_ERR_MOBILEUNABLE:            
        default:
            dwActualResponse = SIMTKIT_TEXTPARSE_SENDDTMF_NOTACCEPTED;
            break;
    }

    _snprintf((char*)pbBuffer, *pdwSize, "14,%d", dwActualResponse);
    pbBuffer[(*pdwSize)-1] = '\0';

    *pdwSize = strlen((char*)pbBuffer)+1;
    
    RETAILMSG(MSG_ON, (TEXT("RilDrv : SIMTKit: -CSimToolkit::SendDTMFResponse\r\n")));

    return hr;  
}

BOOL ParseBytes(const LPBYTE pbData, LPBYTE& rpbData, size_t& rcbData, LPBYTE& rpbPointer)
{
    size_t cbEnd;
    size_t cbCharCount;
    LPBYTE pbDataWalk;
    LPBYTE pchDataStringWalk;
    UINT uiCurByte;
    BOOL fRet = false;

    // Skip any spaces
    SkipChars((LPCSTR)pbData, (LPCSTR&)rpbPointer, " ");
    
    // Create a buffer large enough to hold the unquoted string.
    // Find the end of the encoded string. 
    cbEnd = strspn((char*)rpbPointer, "1234567890ABCDEFabcdef");

    // Make sure some string exists to parse
    if( 0 == cbEnd)
    {     
#ifdef  WAVECOM_DRIVER
        fRet = TRUE;
        cbCharCount=0;
        rcbData = cbCharCount;
        return fRet;
#else       
        ASSERT(FALSE);
        goto Exit;
#endif
    }

    // Make sure that the count of SemiByteChars is even.
    ASSERT(0 == (cbEnd % 2));
        
    cbCharCount = cbEnd / 2;
    // Allocate sufficient storage for the encoded text.
    rpbData = new BYTE[cbCharCount];
    rcbData = cbCharCount;
   
    if (!rpbData)
    {
        ASSERT(FALSE);
        goto Exit;
    }

    // Walk through the encoded text converting it into actual bytes.
    pbDataWalk = rpbData;
    pchDataStringWalk = rpbPointer;
    for (uiCurByte = 0; uiCurByte < cbCharCount; uiCurByte++)
    {
        *pbDataWalk = SemiByteCharsToByte(*pchDataStringWalk, *(pchDataStringWalk + 1));
        pbDataWalk++;
        pchDataStringWalk += 2;
    }

    // Move parsing pointer to current location
    rpbPointer = pchDataStringWalk;

    fRet = true;

Exit:
    return fRet;
        
}


//
// NOTE: caller is responsible for free'ing the storage used by rwszOut
//
BOOL ParseEncodedText(const LPBYTE pbData, DWORD dwEncoding, LPWSTR& rwszOut, size_t& rcbOut, LPBYTE& rpbPointer)
{
    size_t cbCharCount;
    LPBYTE pbTextData = NULL;
    UINT uiUsedLength = 0;
    BOOL fRet = FALSE;

    // Skip any spaces
    SkipChars((LPCSTR)pbData, (LPCSTR&)rpbPointer, " ");

    // Convert the character encoding of the bytes into true bytes.
    if (!ParseBytes(pbData, pbTextData, cbCharCount, rpbPointer))
    {
        goto Error;
    }
#ifdef WAVECOM_DRIVER
    if (0==cbCharCount)
    {
        fRet=true;
        return fRet;
    }
#endif

    // Allocate a buffer large enough to contain all possible unicode strings including null termination.
    // The worst case is 7 bit packed GSM where the number of characters can be 8\7 the size
    // of the byte buffer.
    rcbOut = ((8 * cbCharCount) / 7) + 1;
    rwszOut = new WCHAR[rcbOut];

    if (!rwszOut)
    {
        goto Error;
    }
    
    // Convert the encoded bytes into unicode depending on the encoding scheme
    switch(dwEncoding)
    {
        case SIMTKIT_TEXT_ENCODING_PACKED:
            // This is packed format
            fRet = ConvertGSMToUnicode((char*)pbTextData, cbCharCount, rwszOut, rcbOut, uiUsedLength);
            break;
        case SIMTKIT_TEXT_ENCODING_UNPACKED:
            // Use unpacked format
            fRet = ConvertUnpackedGSMToUnicode((char*)pbTextData, cbCharCount, rwszOut, rcbOut, uiUsedLength);
            break;
        case SIMTKIT_TEXT_ENCODING_UCS2:
            // This is UCS2 format
            fRet = ConvertUCS2ToUnicode((char*)pbTextData, cbCharCount, rwszOut, rcbOut, uiUsedLength);
            break;
        case SIMTKIT_TEXT_ENCODING_ALPHAID:
            // For Alpha identifiers, the text can be encoded in either unpacked GSM alphabet, UCS2, or one of two mixed modes,
            // depending on the first byte of the byte buffer. (GSM 11.11 Annex B)
            fRet = ConvertAlphaIDTextToUnicode((char*)pbTextData, cbCharCount, rwszOut, rcbOut, uiUsedLength);
            break;
            
        default:
            break;
    }
    
    if (!fRet)
    {
        // There was a problem with using the requested scheme
        goto Error;
    }

    // Add the NULL terminator
    rwszOut[uiUsedLength] = TEXT('\0');    

    // Set the return size to the actual buffer length (not the character count).
    rcbOut = (uiUsedLength + 1) * sizeof(WCHAR);
    
    // Skip past any spaces
    SkipChars((LPCSTR)rpbPointer, (LPCSTR&)rpbPointer, " ");

Error:
    if (!fRet)
    {
        delete[] rwszOut;
        rwszOut = NULL;
        rcbOut = 0;
        rpbPointer = pbData;
    }

    if (pbTextData)
    {
        delete[] pbTextData;
    }

    return fRet;    
}


//
// NOTE: caller is responsible for free'ing the storage used by rwszOut
//
BOOL CreateEncodedText(DWORD dwEncoding, const LPWSTR wszIn, LPSTR& rszOut, UINT& ruiOutSize)
{
    LPSTR szConvertedText = NULL;
    UINT uiLen;
    UINT uiConvertLen;
    UINT i;
    LPBYTE pbBytesWalk;
    LPSTR szWalk;
    BOOL fRet = false;


    // Get byte count of text.
    uiLen = lstrlen(wszIn);

    // Create buffer to hold the interim converted text. Worst case on size is UCS2 which is 
    // the same size as the WSTR input buffer.
    uiConvertLen = uiLen * sizeof(WCHAR);
    szConvertedText = new CHAR[uiConvertLen];
    if (!szConvertedText)
    {
        goto Error;
    }

    // Convert the text to the encoded format.
    // uiLen is passed by reference and will contain the actual characters used on return
    // from the unicode conversion routines.
    if (dwEncoding == SIMTKIT_TEXT_ENCODING_UCS2)
    {
        fRet = ConvertUnicodeToUCS2(wszIn, uiLen, (const LPSTR) szConvertedText, uiConvertLen, uiLen);
    }
    else if (dwEncoding == SIMTKIT_TEXT_ENCODING_PACKED)
    {
        fRet = ConvertUnicodeToGSM(wszIn, uiLen, (const LPSTR) szConvertedText, uiConvertLen, uiLen, TRUE);
    }
    else
    {
        ASSERT(dwEncoding == SIMTKIT_TEXT_ENCODING_UNPACKED);
        fRet = ConvertUnicodeToUnpackedGSM(wszIn, uiLen, (const LPSTR) szConvertedText, uiConvertLen, uiLen);
    }

    if (!fRet)
    {
        goto Error;
    }

    if (dwEncoding == SIMTKIT_TEXT_ENCODING_UCS2)
    {
        // Allocate space to hold semi-byte character string, which will be twice the size of the
        // converted text plus null termination.
        ruiOutSize = (uiLen * 2)+1;
        rszOut = new CHAR[ruiOutSize];    
        if(NULL == rszOut)
        {
            fRet = FALSE;
            goto Error;
        }
        // Walk through the characters and convert each to Semi-byte text.
        szWalk = rszOut;
        pbBytesWalk = (BYTE*)szConvertedText;
        for (i = 0; i < uiLen ; i++)
        {
            *szWalk++ = SemiByteToChar(*pbBytesWalk,   TRUE);
            *szWalk++ = SemiByteToChar(*pbBytesWalk++, FALSE);
        }
    
        // null terminate the output buffer.   
        rszOut[ruiOutSize-1] = '\0';
    }
    else
    {
        ruiOutSize = uiLen+1;
        rszOut = new CHAR[ruiOutSize];
        if(NULL == rszOut)
        {
            fRet = FALSE;
            goto Error;
        }
        memcpy(rszOut, szConvertedText, uiLen);
        rszOut[ruiOutSize-1] = '\0';
    }
Error:
    if (!fRet)
    {
        delete[] rszOut;
        rszOut = NULL;
        ruiOutSize = 0;
    }

    if (szConvertedText)
    {
        delete[] szConvertedText;
        szConvertedText = NULL;
    }
    
    return fRet;    
}

//
// Functionality of ConvertAlphaIDTextToUnicode is very similar to CRilSimToolkitCommand::ReadEFADNText in 
// rilsimtkitbyte.cpp, which could not be used due to being too specific and closely coupled with 
// the class it serves. Any changes to this function may also need to be made in ReadEFADNText.
//
BOOL ConvertAlphaIDTextToUnicode(const LPCSTR szInput, const UINT uiInputLength, const LPWSTR wszOutput, const UINT uiOutputLength, UINT& ruiCharactersUsed)
{
    BYTE bEncode;
    LPCSTR szStart;
    LPCSTR szEnd;
    DWORD dwTextLen;
    UINT uiBasePage;
    BOOL fRetVal = FALSE;
    
    // Assert parameters
    ASSERT(NULL != szInput);
    ASSERT(0 < uiInputLength); 
    ASSERT(NULL != wszOutput);
    ASSERT(0 < uiOutputLength);
   
    // Check parameters
    if ((NULL == szInput) || 
        (0 == uiInputLength) || 
        (NULL == wszOutput) ||
        (0 == uiOutputLength))
    {
        return FALSE;
    }

    // For AlphaID text, the string is encoded as per GSM 11.11 Annex B.
    // The 1st byte tells us how the string is encoded or is the first character of the string.
    bEncode = *szInput;

    switch (bEncode)
    {
        // Encoded in UCS2
        case SIMTKIT_TEXTPARSE_ALPHAID_UCS2:

            // The start of the UCS2 encoded text is the 2nd byte.
            szStart = szInput + 1;
            
            // Place the initial end of the UCS2 encoded text at the end of the input.
            szEnd = szInput + uiInputLength - 1;

            if (szStart >= szEnd)
            {
                ASSERT(!"Start of the UCS2 encoding is past the end.");
                return FALSE;
            }
            
            // Remove any unused bytes.
            // Per GSM 11.11, Annex B, we should ignore any FF characters at the end of this string
            while ((szEnd > szStart) && (*szEnd == 0xFFFFFFFF))		    
            {
                szEnd--;
            }
    
            // Convert the trimmed UCS2 encoded text to Unicode.
            fRetVal = ConvertUCS2ToUnicode(szStart, szEnd - szInput, wszOutput, uiOutputLength, ruiCharactersUsed);
            ASSERT(TRUE == fRetVal);
            break;
            
        // Mixed mode encoding using a 8 bit base pointer to a UCS2 half-page.
        case SIMTKIT_TEXTPARSE_ALPHAID_MIXED_8BIT:

            // For 8 bit mixed mode we need at least 3 bytes for the encoding, length, and code page. 
            if (3 > uiInputLength)
            {
                ASSERT(!"Input length not long enough for 8 bit mixed mode.");
                return FALSE;
            }
            
            // The 2nd byte is the length of the string.
            dwTextLen = (DWORD) *(szInput + 1);

            // Check to make sure that the text length is not longer than the input length minus the
            // encoding, length, and 8 bit base pointer bytes.
            if (dwTextLen > (uiInputLength - 3))
            {
                ASSERT(!"Text length encoded in 8 bit mixed mode does not match input buffer length.");
                return FALSE;
            }
    
            // The 3rd byte is bits 15 to 8 of the base pointer.
            uiBasePage = ((DWORD) *(szInput + 2)) << 7;

            // The 4th byte is the start of the mixed mode encoded text.
            szStart = szInput + 3;

            // Convert the mixed mode text to Unicode
            fRetVal = ConvertGSMMixedToUnicode(uiBasePage, szStart, dwTextLen, 
                                                wszOutput, uiOutputLength, ruiCharactersUsed);
            ASSERT(TRUE == fRetVal);
            break;

        // Mixed mode encoding using a 16 bit base pointer to a UCS2 half-page.
        case SIMTKIT_TEXTPARSE_ALPHAID_MIXED_16BIT:

            // For 16 bit mixed mode we need at least 4 bytes for the encoding, length, and code page. 
            if (4 > uiInputLength)
            {
                ASSERT(!"Input length not long enough for 8 bit mixed mode.");
                return FALSE;
            }

            // The 2nd byte after the encoding byte is the length of the string.
            dwTextLen = (DWORD) *(szInput + 1);

            // Check to make sure that the text length is not longer than the input length minus the
            // encoding, length, and 16 bit base pointer.
            if (dwTextLen > (uiInputLength - 4))
            {
                ASSERT(!"Text length encoded in 16 bit mixed mode does not match input buffer length.");
                return FALSE;
            }

            // The 3rd byte and 4th bytes are the 16 bit base pointer.
            uiBasePage = (((DWORD) *(szInput + 2)) << 8) + ((DWORD) *(szInput + 3));

            // The 5th byte is the start of the mixed mode encoded text.
            szStart = szInput + 4;

            // Convert the mixed mode text to Unicode
            fRetVal = ConvertGSMMixedToUnicode(uiBasePage, szStart, dwTextLen, 
                                                wszOutput, uiOutputLength, ruiCharactersUsed);
            ASSERT(TRUE == fRetVal);
            break;
                
        // Otherwise, all characters are 7 bit GSM characters, unpacked.
        default:

            // Convert the unpacked GSM text to Unicode
            fRetVal = ConvertUnpackedGSMToUnicode(szInput, uiInputLength, wszOutput, uiOutputLength, ruiCharactersUsed);

            ASSERT(TRUE == fRetVal);
            break;
    }

    return fRetVal;
}

